﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Configuration;

using log4net;
using log4net.Config;


    /// <summary>
    /// 日志辅助类
    /// </summary>
public class LogHelper
{
    /// <summary>
    /// 日志对象
    /// </summary>
    private static ILog _log = null;

    /// <summary>
    /// 静态构造函数
    /// </summary>
    static LogHelper()
    {
        //配置文件路径
        FileInfo configFile = new FileInfo(string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, ConfigurationManager.AppSettings["Log4netConfigPath"]));

        //配置文件是否存在
        if (!configFile.Exists)
        {
            //创建缺省配置文件
            CreateConfigFile(configFile);
        }

        XmlConfigurator.ConfigureAndWatch(configFile);
        _log = LogManager.GetLogger("Logger");
    }

    /// <summary>
    /// 创建缺省配置文件
    /// </summary>
    /// <param name="fileInfo">文件信息</param>
    private static void CreateConfigFile(FileInfo fileInfo)
    {
        using (StreamWriter sw = File.CreateText(fileInfo.FullName))
        {
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
            sw.WriteLine("<configuration>");
            sw.WriteLine("  <log4net>");
            sw.WriteLine("    <root>");
            sw.WriteLine("      <level value=\"ALL\"/>");
            sw.WriteLine("      <appender-ref ref=\"RollingFileAppender\"/>");
            sw.WriteLine("    </root>");
            sw.WriteLine("    <appender name=\"RollingFileAppender\" type=\"log4net.Appender.RollingFileAppender\">");
            sw.WriteLine("      <param name=\"File\" value=\"Logs/log_\"/>");
            sw.WriteLine("      <param name=\"AppendToFile\" value=\"true\"/>");
            sw.WriteLine("      <param name=\"RollingStyle\" value=\"Date\"/>");
            sw.WriteLine("      <param name=\"DatePattern\" value=\"yyyy-MM-dd&quot;.txt&quot;\"/>");
            sw.WriteLine("      <param name=\"MaximumFileSize \" value=\"1MB\"/>");
            sw.WriteLine("      <param name=\"MaxSizeRollBackups\" value=\"10\"/>");
            sw.WriteLine("      <param name=\"StaticLogFileName\" value=\"false\"/>");
            sw.WriteLine("      <lockingModel type=\"log4net.Appender.FileAppender+MinimalLock\" />");
            sw.WriteLine("      <layout type=\"log4net.Layout.PatternLayout\">");
            sw.WriteLine("        <param name=\"ConversionPattern\" value=\"[时间]:%d%n[级别]:%p%n[内容]:%m%n%n\"/>");
            sw.WriteLine("      </layout>");
            sw.WriteLine("    </appender>");
            sw.WriteLine("  </log4net>");
            sw.WriteLine("</configuration>");
            sw.Close();
        }
    }

    /// <summary>
    /// 日志对象属性
    /// </summary>
    public static ILog Log
    {
        get
        {
            return LogHelper._log;
        }
    }

    #region Write Log

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    public static void Write(LogLevel logLevel, string message)
    {
        Write(logLevel, message, null, null, false);
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    /// <param name="isSendEmail">是否发送邮件消息</param>
    public static void Write(LogLevel logLevel, string message, bool isSendEmail)
    {
        Write(logLevel, message, null, null, isSendEmail);
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    /// <param name="exception">异常信息</param>
    public static void Write(LogLevel logLevel, string message, Exception exception)
    {
        Write(logLevel, message, exception, null, false);
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    /// <param name="exception">异常信息</param>
    /// <param name="isSendEmail">是否发送邮件消息</param>
    public static void Write(LogLevel logLevel, string message, Exception exception, bool isSendEmail)
    {
        Write(logLevel, message, exception, null, isSendEmail);
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    /// <param name="exception">异常信息</param>
    /// <param name="additionalInfo">附加日志信息</param>
    public static void Write(LogLevel logLevel, string message, Exception exception, IDictionary<string, string> additionalInfo)
    {
        Write(logLevel, message, exception, additionalInfo, false);
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="logLevel">日志消息级别</param>
    /// <param name="message">日志摘要</param>
    /// <param name="exception">异常信息</param>
    /// <param name="additionalInfo">附加日志信息</param>
    /// <param name="isSendEmail">是否发送邮件消息</param>
    public static void Write(LogLevel logLevel, string message, Exception exception, IDictionary<string, string> additionalInfo, bool isSendEmail)
    {
        string formatMessage = string.Empty;
        switch (logLevel)
        {
            //调试信息（用于记录一些调试信息）
            case LogLevel.Debug:
                if (Log.IsDebugEnabled)
                {
                    formatMessage = GetFormatMessage(message, additionalInfo);
                    WriteLog(Log.Debug, formatMessage, exception, isSendEmail);
                }
                break;
            case LogLevel.Info:
                //辅助信息（用于记录一些辅助信息）
                if (Log.IsInfoEnabled)
                {
                    formatMessage = GetFormatMessage(message, additionalInfo);
                    WriteLog(Log.Info, formatMessage, exception, isSendEmail);
                }
                break;
            case LogLevel.Warn:
                //警告、注意、通知（用于记录一些需要引起注意问题）
                if (Log.IsWarnEnabled)
                {
                    formatMessage = GetFormatMessage(message, additionalInfo);
                    WriteLog(Log.Warn, formatMessage, exception, isSendEmail);
                }
                break;
            case LogLevel.Error:
                //错误（用户记录一些程序运行时出现错误）
                if (Log.IsErrorEnabled)
                {
                    formatMessage = GetFormatMessage(message, additionalInfo);
                    WriteLog(Log.Error, formatMessage, exception, isSendEmail);
                }
                break;
            case LogLevel.Fatal:
                //致命的、毁灭性的（用户记录一些程序运行时出现的致命错误）
                if (Log.IsFatalEnabled)
                {
                    formatMessage = GetFormatMessage(message, additionalInfo);
                    WriteLog(Log.Fatal, formatMessage, exception, isSendEmail);
                }
                break;
            default:
                throw new ArgumentException("暂不存在当前日志级别！");
        }
    }

    /// <summary>
    /// 根据日志摘要、附加日志信息，获取格式化后的日志消息（摘要）
    /// </summary>
    /// <param name="message">日志摘要</param>
    /// <param name="additionalInfo">附加日志信息</param>
    /// <returns>日志消息</returns>
    private static string GetFormatMessage(string message, IDictionary<string, string> additionalInfo)
    {
        if (!(additionalInfo != null && additionalInfo.Count > 0))
        {
            return message != null && message.Trim() != string.Empty ? message : string.Empty;
        }

        StringBuilder builder = new StringBuilder();
        if (message != null && message.Trim() != string.Empty)
        {
            builder.AppendLine(message);
        }

        foreach (KeyValuePair<string, string> kvp in additionalInfo)
        {
            builder.AppendLine(kvp.Key + " = " + kvp.Value);
        }

        return builder.ToString();
    }

    /// <summary>
    /// 写入日志动作（类型）
    /// </summary>
    /// <param name="mesage">日志摘要</param>
    /// <param name="exception">异常信息</param>
    private delegate void WriteLogAction(object mesage, Exception exception);

    /// <summary>
    /// 根据写入日志动作（类型）、日志摘要、异常信息，写入日志
    /// 并根据是否是否发送邮件消息，进行邮件消息的发送
    /// </summary>
    /// <param name="action">写入日志动作（类型）</param>
    /// <param name="message">日志摘要</param>
    /// <param name="exception">异常信息</param>
    /// <param name="isSendEmail">是否发送邮件消息</param>
    private static void WriteLog(WriteLogAction action, string message, Exception exception, bool isSendEmail)
    {
        action(message, exception);
    }

    #endregion
}

    /// <summary>
    /// 日志消息级别
    /// </summary>
public enum LogLevel
{
    /// <summary>
    /// 调试
    /// </summary>
    Debug,
    /// <summary>
    /// 辅助
    /// </summary>
    Info,
    /// <summary>
    /// 警告、注意、通知
    /// </summary>
    Warn,
    /// <summary>
    /// 错误
    /// </summary>
    Error,
    /// <summary>
    /// 致命、毁灭性
    /// </summary>
    Fatal
}